#include "init.h"
#include "../EXCEPT/except.h"
#include "../VIC/vic_reg.h"
#include "../UART/uart.h"
#include "../MMU/mmu.h"
#include "../PRINT/my_printf.h"

extern int __TEXT_START, __TEXT_END;
extern int __BSS_START, __BSS_END;
extern int __HEAP_START, __HEAP_END;
extern int _undef, _swi, _pabort, _dabort, _irq, _fiq;

extern void rt_system_heap_init(void *begin_addr, void *end_addr);

void init_all(){

    except_vector_init();   // 异常向量表重定向
    other_init();
    FPU_init();             // 使能FPU
    bss_init();             // .bss段初始化

    rt_system_heap_init(&__HEAP_START, &__HEAP_END);

    // mmu_enable();       // 最后初始化比较好，要不然有其它问题

    uart0_init(115200);     // 初始化uart0, 2nboot已经初始化过了

    printf("HEAP: 0x%x 0x%x\r\n", (unsigned int)&__HEAP_START, (unsigned int)&__HEAP_END);

}

void except_vector_init(){
    //两级跳转
    u32 b_code = 0xEA000000 + ((0x7BC0 - 0x08) >> 2);    // b 跳转
    u32 ldr_code = 0xE59FF018;  // ldr pc, [pc, #0x18]

    // Undef Handler
    UndefV = b_code;
    UndefVGoto = ldr_code;
    UndefVval = (u32)&_undef;

    // SWI Handler
    SWIV = b_code;
    SWIVGoto = ldr_code;
    SWIVval = (u32)&_swi;

    // PAbort Handler
    PAbortV = b_code;
    PAbortVGoto = ldr_code;
    PAbortVval = (u32)&_pabort;

    // DAbort Handler
    DAbortV = b_code;
    DAbortVGoto = ldr_code;
    DAbortVval = (u32)&_dabort;

    // IRQ Handler
    IRQV = b_code;
    IRQVGoto = ldr_code;
    IRQVval = (u32)&_irq;

    // printf("[%x] [%x] [%x]\r\n", (u32)&except_irq, except_irq, (u32)except_dabort);

}

void bss_init(){
    int *start = &__BSS_START;
    int size = &__BSS_END - &__BSS_START;
    int i = 0;

    for(; i < size; i += 4){
        *(start + i) = 0;
    }
}

void FPU_init(){
    __asm__(
        "MRC p15, 0, r0, c1, c1, 2\n"
        "ORR r0, r0, #3<<10\n"
        "MCR p15, 0, r0, c1, c1, 2\n"
        "LDR r0, =(0xF << 20)\n"
        "MCR p15, 0, r0, c1, c0, 2\n"
        "MOV r3, #0x40000000\n"
        "VMSR FPEXC, r3\n"
    );
}

void mmu_enable(){

    create_page_table();     // 创建段页表
 
    __asm__(
        "ldr r0, =0x50000000\n"
        "mcr p15, 0, r0, c2, c0, 0\n"
    );  // 把页表基址告诉cp15

    __asm__(
        "ldr r0, =0xFFFFFFFF\n"
        "mcr p15, 0, r0, c3, c0, 0\n"
    );  // 设置域为0xffffffff, 即所有域都不进行权限检查

    __asm__(
        "mrc p15, 0, r0, c1, c0, 0\n"
        "orr r0, r0, #(1 << 12)\n"     // 使能ICache
        // "bic r0, r0, #(1 << 12)\n"     // 关闭ICache
        "orr r0, r0, #(1 << 2)\n"     // 使能DCache
        "orr r0, r0, #(1 << 0)\n"     // 使能MMU
        "mcr p15, 0, r0, c1, c0, 0\n"
    ); 

}

void other_init(){
    
    __asm__("cpsie i\n");  // 开启IRQ

    GICC_CTLR = 0;      // 绕过GIC
    
}

